unit uMainFrm;

interface

uses
  Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
  Dialogs,

  GlScene, GlObjects, GlCadencer, GLWin32Viewer, GLRenderContextInfo, GlWindowsFont, GlHudObjects,
  GlMaterial,
  VectorGeometry,

  uSimpleButton, uSimplePanel, uTweener;
type
  TMenuButton = class
    fPanel: TGlHudSprite;
    fSprite: TSimpleButton;
    fPanelText: String;
    fX: Single;
  end;

  TPanelState = (ps_GoHide, ps_GoShow);

  TfrmMain = class(TForm)
    procedure FormCreate(Sender: TObject);
    procedure FormActivate(Sender: TObject);
    procedure FormDestroy(Sender: TObject);
  private
    {Main Objects}
    fGlScene: TGlScene;
    fCadencer: TGLCadencer;
    fViewer: TGLSceneViewer;
    fCamera: TGlCamera;
    fMainDummy: TGlDummyCube;
    fFpsTimer: Single;
    fMatLib: TGlMaterialLibrary;

    {Text Objects}
    fWinFont: TGLWindowsBitmapFont;
    fHudText: TGLHUDText;
    fBack: TGlHudSprite;
    fLeftPanel: TGlHudSprite;

    {SimpleButton}
    fButtons: TList;

    {fPanel}
    fPanelText: TGLHUDText; 
    fPanel: TSimplePanel;
    fPanelX: Single;
    fPanelState: TPanelState;
    fPanelItem: TMenuButton;

    {Demo Name}
    fDemoName: TGlHudSprite;

    {Tweener}
    fTweener: TTweener;
  public
    Procedure OnMouseEvent(aSender: TSimpleButton; aOldState, aNewState: TButtonState);
    Procedure OnMouseClick(aSender: TSimpleButton);
    Function AddButton(aMatName: String; aX, aY: Integer; aPanelText: String): TMenuButton;
    Function GetButtonByIndex(aIndex: Integer): TMenuButton;
    Function GetButtonBySprite(aSprite: TGlHudSprite): TMenuButton;
  public
    Procedure InitFontAndSprites;
    Procedure InitMaterials;
    Procedure InitTweener;
    Procedure OnCadencerProgress(Sender : TObject; const deltaTime, newTime : Double);
  end;

var
  frmMain: TfrmMain;

implementation
uses
  glKeyboard, GLCrossPlatform,
  uDemoInit;
{$R *.dfm}

procedure TfrmMain.FormCreate(Sender: TObject);
begin
  fFpsTimer := 0;
  CreateDemo(self, fGlScene, fCadencer, fViewer);
  
  fCamera := TGlCamera.CreateAsChild(fGlScene.Objects);
  with fCamera do
  begin
    Position.SetPoint(0, 0, 5);
    Direction.SetVector(0, 0, -1);
    Up.SetVector(0, 1, 0);
    CameraStyle := csOrthogonal;
    SceneScale := 0.1;
  end;

  fMainDummy := TGLDummyCube.CreateAsChild(fGlScene.Objects);
  fMainDummy.ObjectsSorting := osNone;

  fViewer.Camera := fCamera;
  fCadencer.OnProgress := OnCadencerProgress;

  fMatLib := TGlMaterialLibrary.Create(self);

  InitMaterials;
  InitTweener;
  InitFontAndSprites;
end;

procedure TfrmMain.FormActivate(Sender: TObject);
begin
  fCadencer.Enabled := true;
end;

Procedure TfrmMain.OnMouseEvent(aSender: TSimpleButton; aOldState, aNewState: TButtonState);
var
  btn: TMenuButton;
begin
  btn := GetButtonBySprite(aSender);
  if btn = nil then
    exit;

  if aNewState = bs_MouseIn then
    fTweener.AddTweenPSingle(@btn.fX, ts_ElasticEaseIn, aSender.Position.X, 50, 1.5)
  else
    fTweener.AddTweenPSingle(@btn.fX, ts_ElasticEaseIn, aSender.Position.X, -5, 1.5);
end;

Procedure TfrmMain.OnMouseClick(aSender: TSimpleButton);
begin
  fPanelState := ps_GoHide;
  fPanelItem := GetButtonBySprite(aSender);
  fTweener.AddTweenPSingle(@fPanelX, ts_ExpoEaseIn, fPanel.Position.X, 550, 2.0);
end;

Function TfrmMain.AddButton(aMatName: String; aX, aY: Integer; aPanelText: String): TMenuButton;
begin
  result := TMenuButton.Create;
  with result do
  begin
    fPanelText := aPanelText;

    fSprite := TSimpleButton.CreateAsChild(fMainDummy);
    fX := aX;
    with fSprite do
    begin
      Material.LibMaterialName := aMatName;
      Material.MaterialLibrary := fMatLib;
      Width  := 256;
      Height := 64;
      Position.SetPoint(aX, aY, 0);
    end;
    fSprite.OnMouseEvent := OnMouseEvent;
    fSprite.OnMouseClick := OnMouseClick;

    fPanel := TGLHudSprite.CreateAsChild(fMainDummy);
    with fPanel do
    begin
      Material.LibMaterialName := 'panel_1';
      Material.MaterialLibrary := fMatLib;
      Width  := 16;
      Height := 64;
      Position.SetPoint(aX + 30, aY + 5, 0);
    end;
  end;
  fButtons.Add(result);
end;

Function TfrmMain.GetButtonByIndex(aIndex: Integer): TMenuButton;
begin
  result := fButtons.Items[aIndex];
end;

Function TfrmMain.GetButtonBySprite(aSprite: TGlHudSprite): TMenuButton;
var
  i: integer;
begin
  result := nil;
  for i := 0 to fButtons.Count - 1 do
    if GetButtonByIndex(i).fSprite = aSprite then
    begin
      result := GetButtonByIndex(i);
      break;
    end;
end;

Procedure TfrmMain.InitFontAndSprites;
  Function AddSprite(aMatName: String; aX, aY: integer; aW, aH: Integer): TGlHudSprite;
  begin
    result := TGlHudSprite.CreateAsChild(fMainDummy);
    with result do
    begin
      Material.LibMaterialName := aMatName;
      Material.MaterialLibrary := fMatLib;
      Width  := aW;
      Height := aH;
      Position.SetPoint(aX, aY, 0);
    end;
  end;
begin
  fWinFont := TGLWindowsBitmapFont.Create(self);
  fWinFont.Font.Name := 'Arial';

  fBack := AddSprite('back', 200, 200, 400, 400);
  fDemoName := AddSprite('demoname', 200, 30, 256, 32);

  AddButton('newgame', -5, 100, 'New Game' + #13#10#13#10 + 'Here you can add your game' + #13#10 + 'It could be puzzle, arcade' + #13#10 + 'or something else!');
  AddButton('options', -5, 170, 'Options' + #13#10#13#10 + 'Sounds and Music volume, ' + #13#10 + 'fullscreen and show/hide tips');
  AddButton('help',    -5, 240, 'Help' + #13#10#13#10 + 'Instructions, keys and other');
  AddButton('exit',    -5, 310, 'Exit' + #13#10#13#10 + 'Yes/No');

  fLeftPanel := AddSprite('back', 5, 200, 30, 400);

  fPanelX := 550; {280}
  fPanelState := ps_GoHide;
  fPanelItem := nil;

  fPanel := TSimplePanel.CreateAsChild(fMainDummy);
  with fPanel do
  begin
    Position.SetPoint(fPanelX, 190, 0);
    Width := 200;
    Height := 150;
    Material.LibMaterialName := 'panel_2';
    Material.MaterialLibrary := fMatLib;
  end;

  fPanelText := TGLHUDText.CreateAsChild(fMainDummy);
  with fPanelText do
  begin
    BitmapFont := fWinFont;
    Text := 'Test';
    Position.SetPoint(fPanelX, 180, 0);
    ModulateColor.SetColor(60/255, 135/255, 147/255, 1);
    Alignment := taRightJustify;
    Layout := tlCenter;
  end;

  fHudText := TGLHUDText.CreateAsChild(fMainDummy);
  with fHudText do
  begin
    BitmapFont := fWinFont;
    Text := 'Lampogolovii presents ''Simple Buttons Demo''';
    Position.SetPoint(390, 380, 0);
    ModulateColor.SetColor(92/255, 165/255, 177/255, 1);
    Alignment := taRightJustify;
  end;
end;

Procedure TfrmMain.InitMaterials;
begin
  AddSimpleMaterial(fMatLib, 'back', 215, 236, 230, 255);
  AddMaterial(fMatLib, str_ImagesFolder + '\SimpleButton\newgame_1.png', 'newgame');
  AddMaterial(fMatLib, str_ImagesFolder + '\SimpleButton\options_1.png', 'options');
  AddMaterial(fMatLib, str_ImagesFolder + '\SimpleButton\help_1.png', 'help');
  AddMaterial(fMatLib, str_ImagesFolder + '\SimpleButton\exit_1.png', 'exit');
  AddMaterial(fMatLib, str_ImagesFolder + '\SimpleButton\panel_1.png', 'panel_1');
  AddMaterial(fMatLib, str_ImagesFolder + '\SimpleButton\panel_2.png', 'panel_2');
  AddMaterial(fMatLib, str_ImagesFolder + '\SimpleButton\demoname.png', 'demoname');
end;

Procedure TfrmMain.InitTweener;
begin
  fButtons := TList.Create;
  fTweener := TTweener.Create; 
end;

Procedure TfrmMain.OnCadencerProgress(Sender : TObject; const deltaTime, newTime : Double);
var
  MPos: TPoint;
  i: integer;
begin
  fTweener.Update(deltaTime);

  fPanel.Position.X := fPanelX;
  fPanelText.Position.X := fPanelX + 85;

  if (fPanelItem <> nil) then
    if (fPanelState = ps_GoHide) and (fPanelX > 530) then
    begin
      fPanelState := ps_GoShow;
      fPanelText.Text := fPanelItem.fPanelText;
      fTweener.AddTweenPSingle(@fPanelX, ts_ExpoEaseIn, fPanel.Position.X, 280, 2.0);
    end;

  GetCursorPos(Mpos);
  MPos := fViewer.ScreenToClient(MPos);

  for i := 0 to fButtons.Count - 1 do
    with GetButtonByIndex(i) do
    begin
      fSprite.SetMouseState(MPos.X, MPos.Y, IsKeyDown(Vk_LButton));
      fSprite.Position.X := fX;
    end;
end;

procedure TfrmMain.FormDestroy(Sender: TObject);
begin
  while fButtons.Count > 0 do
  begin
    GetButtonByIndex(0).Free;    
    fButtons.Delete(0);
  end;
  FreeAndNil(fButtons);
  FreeAndNil(fTweener);
end;

end.
